﻿using System;
using System.IO;

namespace ShareHelper
{
    /// <summary>
    /// 内存流 扩展类
    /// </summary>
    public static class StreamHelper
    {
        /// <summary>
        /// 获取流剩余数据长度
        /// </summary>
        /// <param name="ms"></param>
        /// <returns></returns>
        public static long GetLength(this MemoryStream ms)
        {
            return ms.Length - ms.Position;
        }

        /// <summary>
        ///尝试从数据流读取一个整数 数据流剩余数量大于4 则可成功读取
        /// </summary>
        /// <param name="ms"></param>
        /// <param name="result"></param>
        /// <param name="reverse"></param>
        /// <returns></returns>
        public static bool TryInt(this MemoryStream ms, out int result, bool reverse = false)
        {
            if (ms.TryGetBuffer(out byte[] data, 4, reverse))
            {
                result = BitConverter.ToInt32(data, 0);
                return true;
            }
            result = 0;
            return false;
        }

        /// <summary>
        ///尝试从数据流读一个无符号整数
        /// </summary>
        /// <param name="ms"></param>
        /// <param name="result"></param>
        /// <returns></returns>
        public static bool TryUInt(this MemoryStream ms, out uint result)
        {
            if (ms.TryGetBuffer(out byte[] data, 4, true))
            {
                result = BitConverter.ToUInt32(data, 0);
                return true;
            }
            result = 0;
            return false;
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="ms"></param>
        /// <param name="data"></param>
        /// <param name="len"></param>
        /// <param name="reverse"></param>
        /// <returns></returns>
        public static bool TryGetBuffer(this MemoryStream ms, out byte[] data, int len, bool reverse = false)
        {
            if (len > ms.GetLength())
            {
                data = null;
                return false;
            }
            data = new byte[len];
            ms.Read(data, 0, len);
            if (reverse)
            {
                Array.Reverse(data);
            }
            return true;
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="ms"></param>
        /// <param name="reverse"></param>
        /// <returns></returns>
        public static uint GetUint(this MemoryStream ms, bool reverse = false)
        {
            var data = ms.GetBuffer(4, reverse);
            return BitConverter.ToUInt32(data, 0);
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="ms"></param>
        /// <param name="reverse"></param>
        /// <returns></returns>
        public static int Getint(this MemoryStream ms, bool reverse = false)
        {
            var data = ms.GetBuffer(4, reverse);
            return BitConverter.ToInt32(data, 0);
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="ms"></param>
        /// <param name="reverse"></param>
        /// <returns></returns>
        public static short GetShort(this MemoryStream ms, bool reverse = false)
        {
            var data = ms.GetBuffer(2, reverse);
            return BitConverter.ToInt16(data, 0);
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="ms"></param>
        /// <param name="result"></param>
        /// <param name="reverse"></param>
        /// <returns></returns>
        public static bool TryShort(this MemoryStream ms, out short result, bool reverse = false)
        {
            if (ms.TryGetBuffer(out byte[] data, 2, reverse))
            {
                result = BitConverter.ToInt16(data, 0);
                return true;
            }
            result = 0;
            return false;
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="ms"></param>
        /// <param name="len"></param>
        /// <param name="reverse"></param>
        /// <returns></returns>
        public static byte[] GetBuffer(this MemoryStream ms, int len, bool reverse = false)
        {
            var data = new byte[len];
            ms.Read(data, 0, len);
            if (reverse)
            {
                Array.Reverse(data);
            }
            return data;
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="ms"></param>
        /// <returns></returns>
        public static byte GetByte(this MemoryStream ms)
        {
            int len = 1;
            var data = new byte[len];
            ms.Read(data, 0, len);
            return data[0];
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="ms"></param>
        /// <param name="value"></param>
        /// <param name="reverse"></param>
        public static void Write(this MemoryStream ms, int value, bool reverse = false)
        {
            Write(ms, BitConverter.GetBytes(value), reverse);
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="ms"></param>
        /// <param name="value"></param>
        /// <param name="reverse"></param>
        public static void Write(this MemoryStream ms, short value, bool reverse = false)
        {
            Write(ms, BitConverter.GetBytes(value), reverse);
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="ms"></param>
        /// <param name="value"></param>
        /// <param name="reverse"></param>
        public static void Write(this MemoryStream ms, uint value, bool reverse = false)
        {
            ms.Write(BitConverter.GetBytes(value), reverse);
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="ms"></param>
        /// <param name="data"></param>
        /// <param name="reverse"></param>
        public static void Write(this MemoryStream ms, byte[] data, bool reverse = false)
        {
            if (data?.Length > 0)
            {
                if (reverse)
                    Array.Reverse(data);
                ms.Write(data, 0, data.Length);
            }
        }

        /// <summary>复制数组</summary>
        /// <param name="src">源数组</param>
        /// <param name="offset">起始位置</param>
        /// <param name="count">复制字节数</param>
        /// <returns>返回复制的总字节数</returns>
        public static byte[] ReadBytes(this byte[] src, int offset = 0, int count = -1)
        {
            if (count == 0) return new byte[0];

            // 即使是全部，也要复制一份，而不只是返回原数组，因为可能就是为了复制数组
            if (count < 0) count = src.Length - offset;

            var bts = new byte[count];
            Buffer.BlockCopy(src, offset, bts, 0, bts.Length);
            return bts;
        }
    }
}